#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
using System.Windows.Media;
using System.Collections;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media.Animation;
using UTable.Input.MultiTouch;

namespace UTable.Objects.Controls
{
    public partial class UBookViewer : ItemsControl, IControl
	{

		#region Constructors

		public UBookViewer()
        {
            InitializeComponent();
            InitializeIControlPart();
        }

        static UBookViewer()
        {
            DisplayModeProperty = DependencyProperty.Register("DisplayMode", typeof(BookDisplayMode), typeof(UBookViewer), new PropertyMetadata(BookDisplayMode.Normal, new PropertyChangedCallback(OnDisplayModeChanged)));
            CurrentPageProperty = DependencyProperty.Register("CurrentPage", typeof(BookCurrentPage), typeof(UBookViewer), new PropertyMetadata(BookCurrentPage.RightSheet, new PropertyChangedCallback(OnCurrentPageChanged)));
            PresentModeProperty = DependencyProperty.Register("PresentMode", typeof(BookPresentMode), typeof(UBookViewer), new PropertyMetadata(BookPresentMode.TwoPages, new PropertyChangedCallback(OnPresentModeChanged)));
		}

		#endregion

		private static void OnDisplayModeChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
        {
            BookDisplayMode mode = (BookDisplayMode)args.NewValue;
            UBookViewer book = source as UBookViewer;
            if (mode == BookDisplayMode.Normal)
            {
                //book.translate.X = 0;
                //book.scale.ScaleX = 1;
                //book.scale.ScaleY = 1;
                book.translate.BeginAnimation(TranslateTransform.XProperty, null);
                book.scale.BeginAnimation(ScaleTransform.ScaleXProperty, null);
            }
            else
            {
                if (book.CurrentPage == BookCurrentPage.LeftSheet)
                    book.AnimateToLeftSheet();
                else
                    book.AnimateToRightSheet();
            }
        }

        private static void OnCurrentPageChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
        {
            BookCurrentPage currentPage = (BookCurrentPage)args.NewValue;
            UBookViewer b = source as UBookViewer;
            if (currentPage == BookCurrentPage.LeftSheet)
                b.AnimateToRightSheet();
            else
                b.AnimateToLeftSheet();
        }

        private static void OnPresentModeChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
        {
            UBookViewer book = source as UBookViewer;
            //book.presentmode = (BookPresentMode)args.NewValue;
            //BookPage bp0 = book.GetTemplateChild("sheet0") as BookPage;
            if (((BookPresentMode)args.NewValue) == BookPresentMode.TwoPages)
            {
                book.CurrentSheetIndex = (book.CurrentSheetIndex + 1) / 2;
                book.Width *= 2;
            }
            else
            {
                book.CurrentSheetIndex = book.CurrentSheetIndex * 2;
                book.Width /= 2;
            }
            book.RefreshSheetsContent();
        }
        
		public static DependencyProperty DisplayModeProperty;
        public static DependencyProperty CurrentPageProperty;
        public static DependencyProperty PresentModeProperty;

        private PageStatus _status = PageStatus.None;
        private DataTemplate defaultDataTemplate;

        private void OnLoaded(object sender, RoutedEventArgs args)
        {
            UBookPage bp0 = GetTemplateChild("sheet0") as UBookPage;
            UBookPage bp1 = GetTemplateChild("sheet1") as UBookPage;
            if ((bp0 == null) || (bp1 == null))
                return;
            /*
            bp0.PageBack +=new RoutedEventHandler(OnPageBack);
            bp0.PageTurned += new RoutedEventHandler(OnLeftPageTurned);
            bp0.MouseDown += new MouseButtonEventHandler(OnLeftMouseDown);
            bp1.PageBack +=new RoutedEventHandler(OnPageBack);
            bp1.PageTurned += new RoutedEventHandler(OnRightPageTurned);
            bp1.MouseDown += new MouseButtonEventHandler(OnRightMouseDown);
            */


            defaultDataTemplate = (DataTemplate)Resources["defaultDataTemplate"];
            Read<PageStatus> GetStatus = delegate() { return _status; };
            Action<PageStatus> SetStatus = delegate(PageStatus ps) { _status = ps; };
            bp0.GetStatus += GetStatus;
            bp0.SetStatus += SetStatus;
            bp1.GetStatus += GetStatus;
            bp1.SetStatus += SetStatus;

            RefreshSheetsContent();

        }

        protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);
            if (CheckCurrentSheetIndex())
            {
                CurrentSheetIndex = GetItemsCount() / 2;
            }
            else
                RefreshSheetsContent();
        }

        protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
        {
            base.OnItemsSourceChanged(oldValue, newValue);
            if (CheckCurrentSheetIndex())
            {
                CurrentSheetIndex = GetItemsCount() / 2;
            }
            else
                RefreshSheetsContent();
        }

        private int _currentSheetIndex = 0;

		public void RefreshZIndex()
		{
			UBookPage bp0 = GetTemplateChild("sheet0") as UBookPage;
			UBookPage bp1 = GetTemplateChild("sheet1") as UBookPage;

			if ((bp0 == null) || (bp1 == null))
				return;

			Canvas.SetZIndex((bp0 as UBookPage), 0);
			Canvas.SetZIndex((bp1 as UBookPage), 1);
		}

        public void AnimateToNextPage(bool fromTop, int duration)
        {
            if (CurrentSheetIndex + 1 <= GetItemsCount() / 2)
            {
				UBookPage bp0 = GetTemplateChild("sheet0") as UBookPage;
				UBookPage bp1 = GetTemplateChild("sheet1") as UBookPage;
				if ((bp0 == null) || (bp1 == null))
					return;

				RefreshZIndex();
                bp1.AutoTurnPage(fromTop ? CornerOrigin.TopRight : CornerOrigin.BottomRight, duration);
            }
        }

        public void AnimateToPreviousPage(bool fromTop, int duration)
        {
            if (CurrentSheetIndex > 0)
            {
                UBookPage bp0 = GetTemplateChild("sheet0") as UBookPage;
                UBookPage bp1 = GetTemplateChild("sheet1") as UBookPage;

                if ((bp0 == null) || (bp1 == null))
                    return;

                Canvas.SetZIndex((bp1 as UBookPage), 0);
                Canvas.SetZIndex((bp0 as UBookPage), 1);
                bp0.AutoTurnPage(fromTop ? CornerOrigin.TopLeft : CornerOrigin.BottomLeft, duration);
            }
        }

        public int CurrentSheetIndex
        {
            get { return _currentSheetIndex; }
            set
            {
                if (PresentMode == BookPresentMode.TwoPages)
                {
                    if (_status != PageStatus.None) return;

                    if (_currentSheetIndex != value)
                    {
                        if ((value >= 0) && (value <= GetItemsCount() / 2))
                        {
                            _currentSheetIndex = value;
                            RefreshSheetsContent();
                        }
                        else
                            throw new Exception("Index out of bounds");
                    }
                }
                else
                {
                    if (_status != PageStatus.None && _status != PageStatus.Dragging) return;

                    if (_currentSheetIndex != value)
                    {
                        if ((value >= 0) && value <= GetItemsCount())
                        {
                            _currentSheetIndex = value;
                            RefreshSheetsContent();
                        }
                    }
                }
            }
        }

        protected virtual bool CheckCurrentSheetIndex()
        {
            return CurrentSheetIndex > (GetItemsCount() / 2);
		}

		public int GetItemsCount()
        {
            if (ItemsSource != null)
            {
                if (ItemsSource is ICollection)
                    return (ItemsSource as ICollection).Count;
                int count = 0;
                foreach (object o in ItemsSource) count++;
                return count;
            }
            return Items.Count;
		}

		private void RefreshSheetsContent_TwoPageMode()
        {
            UBookPage bp0 = GetTemplateChild("sheet0") as UBookPage;
            if (bp0 == null)
                return;

            UBookPage bp1 = GetTemplateChild("sheet1") as UBookPage;
            if (bp1 == null)
                return;
            bp0.IsEnabled = true;
            bp0.IsEnabled = true;
            ContentPresenter sheet0Page0Content = bp0.FindName("page0") as ContentPresenter;
            ContentPresenter sheet0Page1Content = bp0.FindName("page1") as ContentPresenter;
            ContentPresenter sheet0Page2Content = bp0.FindName("page2") as ContentPresenter;

            ContentPresenter sheet1Page0Content = bp1.FindName("page0") as ContentPresenter;
            ContentPresenter sheet1Page1Content = bp1.FindName("page1") as ContentPresenter;
            ContentPresenter sheet1Page2Content = bp1.FindName("page2") as ContentPresenter;

            Visibility bp0Visibility = Visibility.Visible;
            Visibility bp1Visibility = Visibility.Visible;

            bp1.IsRightSideEnabled = true;
            bp1.IsLeftSideEnabled = false;
            bp0.IsRightSideEnabled = false;
            bp0.IsLeftSideEnabled = true;

            Visibility sheet0Page0ContentVisibility = Visibility.Visible;
            Visibility sheet0Page1ContentVisibility = Visibility.Visible;
            Visibility sheet0Page2ContentVisibility = Visibility.Visible;
            Visibility sheet1Page0ContentVisibility = Visibility.Visible;
            Visibility sheet1Page1ContentVisibility = Visibility.Visible;
            Visibility sheet1Page2ContentVisibility = Visibility.Visible;

            DataTemplate dt = ItemTemplate;
            if (dt == null)
                dt = defaultDataTemplate;

            sheet0Page0Content.ContentTemplate = dt;
            sheet0Page1Content.ContentTemplate = dt;
            sheet0Page2Content.ContentTemplate = dt;
            sheet1Page0Content.ContentTemplate = dt;
            sheet1Page1Content.ContentTemplate = dt;
            sheet1Page2Content.ContentTemplate = dt;

            sheet0Page2ContentVisibility = _currentSheetIndex == 1 ? Visibility.Hidden : Visibility.Visible;
            int count = GetItemsCount();
            int sheetCount = count / 2;
            bool isOdd = (count % 2) == 1;

            if (_currentSheetIndex == sheetCount)
            {
                if (isOdd)
                {
                    bp1.IsRightSideEnabled = false;
                }
                else
                    bp1Visibility = Visibility.Hidden;
            }

            if (_currentSheetIndex == sheetCount - 1)
            {
                if (!isOdd)
                    sheet1Page2ContentVisibility = Visibility.Hidden;
            }

            if (_currentSheetIndex == 0)
            {
                sheet0Page0Content.Content = null;
                sheet0Page1Content.Content = null;
                sheet0Page2Content.Content = null;
                bp0.IsEnabled = false;
                bp0Visibility = Visibility.Hidden;
            }
            else
            {
                sheet0Page0Content.Content = GetPage(2 * (CurrentSheetIndex - 1) + 1);
                sheet0Page1Content.Content = GetPage(2 * (CurrentSheetIndex - 1));
                sheet0Page2Content.Content = GetPage(2 * (CurrentSheetIndex - 1) - 1);
                bp0.IsEnabled = true;
            }

            sheet1Page0Content.Content = GetPage(2 * CurrentSheetIndex);
            sheet1Page1Content.Content = GetPage(2 * CurrentSheetIndex + 1);
            sheet1Page2Content.Content = GetPage(2 * CurrentSheetIndex + 2);

            bp0.Visibility = bp0Visibility;
            bp1.Visibility = bp1Visibility;

            sheet0Page0Content.Visibility = sheet0Page0ContentVisibility;
            sheet0Page1Content.Visibility = sheet0Page1ContentVisibility;
            sheet0Page2Content.Visibility = sheet0Page2ContentVisibility;
            sheet1Page0Content.Visibility = sheet1Page0ContentVisibility;
            sheet1Page1Content.Visibility = sheet1Page1ContentVisibility;
            sheet1Page2Content.Visibility = sheet1Page2ContentVisibility;

        }
        private void RefreshSheetsContent_OnePageMode()
        {
            UBookPage bp0 = GetTemplateChild("sheet0") as UBookPage;
            bp0.IsEnabled = false;
            UBookPage bp1 = GetTemplateChild("sheet1") as UBookPage;
            if (bp1 == null)
                return;
            ContentPresenter sheet1Page0Content = bp1.FindName("page0") as ContentPresenter;
            ContentPresenter sheet1Page1Content = bp1.FindName("page1") as ContentPresenter;
            ContentPresenter sheet1Page2Content = bp1.FindName("page2") as ContentPresenter;

            //Visibility bp0Visibility = Visibility.Hidden;
            Visibility bp1Visibility = Visibility.Visible;

            bp1.IsRightSideEnabled = true;

            //Visibility sheet0Page0ContentVisibility = Visibility.Hidden;
            //Visibility sheet0Page1ContentVisibility = Visibility.Hidden;
            //Visibility sheet0Page2ContentVisibility = Visibility.Hidden;
            Visibility sheet1Page0ContentVisibility = Visibility.Visible;
            Visibility sheet1Page1ContentVisibility = Visibility.Visible;
            Visibility sheet1Page2ContentVisibility = Visibility.Visible;

            DataTemplate dt = ItemTemplate;
            if (dt == null)
                dt = defaultDataTemplate;

            //sheet0Page0Content.ContentTemplate = dt;
            //sheet0Page1Content.ContentTemplate = dt;
            //sheet0Page2Content.ContentTemplate = dt;
            sheet1Page0Content.ContentTemplate = dt;
            sheet1Page1Content.ContentTemplate = dt;
            sheet1Page2Content.ContentTemplate = dt;

            //sheet0Page2ContentVisibility = _currentSheetIndex == 1 ? Visibility.Hidden : Visibility.Visible;
            int count = GetItemsCount();
            int sheetCount = count / 2;
            bool isOdd = (count % 2) == 1;

            sheet1Page0Content.Content = GetPage(CurrentSheetIndex);
            sheet1Page1Content.Content = GetPage(CurrentSheetIndex);

            if (CurrentSheetIndex == 0)
                bp1.IsLeftSideEnabled = false;
            else
                bp1.IsLeftSideEnabled = true;

            if (CurrentSheetIndex == count - 1)
            {
                bp1.IsRightSideEnabled = false;
                sheet1Page2ContentVisibility = Visibility.Hidden;
                sheet1Page2Content.Content = null;
            }
            else
            {
                bp1.IsRightSideEnabled = true;
                sheet1Page2ContentVisibility = Visibility.Visible;
                sheet1Page2Content.Content = GetPage(CurrentSheetIndex + 1);
            }

            bp1.Visibility = bp1Visibility;

            sheet1Page0Content.Visibility = sheet1Page0ContentVisibility;
            sheet1Page1Content.Visibility = sheet1Page1ContentVisibility;
            sheet1Page2Content.Visibility = sheet1Page2ContentVisibility;

        }
        private void RefreshSheetsContent()
        {
            Grid grid = GetTemplateChild("bookgrid") as Grid;
            if (grid == null) return;
            if (PresentMode == BookPresentMode.OnePage)
            {
                grid.ColumnDefinitions[0].Width = new GridLength(0);
                RefreshSheetsContent_OnePageMode();
            }
            else
            {
                grid.ColumnDefinitions[0].Width = grid.ColumnDefinitions[1].Width;
                RefreshSheetsContent_TwoPageMode();
            }
        }
        private void OnLeftMouseDown(object sender, MouseButtonEventArgs args)
        {
            UBookPage bp0 = GetTemplateChild("sheet0") as UBookPage;
            UBookPage bp1 = GetTemplateChild("sheet1") as UBookPage;
            Canvas.SetZIndex((bp0 as UBookPage), 1);
            Canvas.SetZIndex((bp1 as UBookPage), 0);
        }
        private void OnRightMouseDown(object sender, MouseButtonEventArgs args)
        {
            UBookPage bp0 = GetTemplateChild("sheet0") as UBookPage;
            UBookPage bp1 = GetTemplateChild("sheet1") as UBookPage;
            Canvas.SetZIndex((bp0 as UBookPage), 0);
            Canvas.SetZIndex((bp1 as UBookPage), 1);
        }
        private void OnLeftPageTurned(object sender, RoutedEventArgs args)
        {
            CurrentSheetIndex--;
        }
        private void OnRightPageTurned(object sender, RoutedEventArgs args)
        {
            CurrentSheetIndex++;
        }
        private void OnPageBack(object sender, RoutedEventArgs args)
        {
            if (PresentMode == BookPresentMode.OnePage)
                CurrentSheetIndex = CurrentSheetIndex - 1;
        }
        
		public BookDisplayMode DisplayMode
        {
            get { return (BookDisplayMode)GetValue(UBookViewer.DisplayModeProperty); }
            set
            {
                if (!GetValue(UBookViewer.DisplayModeProperty).Equals(value))
                    SetValue(UBookViewer.DisplayModeProperty, value);
            }
        }

        public BookCurrentPage CurrentPage
        {
            get { return (BookCurrentPage)GetValue(UBookViewer.CurrentPageProperty); }
            set
            {
                if (!GetValue(UBookViewer.CurrentPageProperty).Equals(value))
                    SetValue(UBookViewer.CurrentPageProperty, value);
            }
        }
        
		public BookPresentMode PresentMode
        {
            get { return (BookPresentMode)GetValue(UBookViewer.PresentModeProperty); }
            set
            {
                if (!GetValue(UBookViewer.PresentModeProperty).Equals(value))
                    SetValue(UBookViewer.PresentModeProperty, value);
            }
        }

		private double gripSize = 40;

		public double GripSize
		{
			get { return gripSize; }
			set 
			{ 
				gripSize = value;
				UBookPage bp0 = GetTemplateChild("sheet0") as UBookPage;
				UBookPage bp1 = GetTemplateChild("sheet1") as UBookPage;
				if (bp0 != null)
					bp0.GripSize = value;
				if (bp1 != null)
					bp1.GripSize = value;
			}
		}

        private void AnimateToLeftSheet()
        {
            DoubleAnimation translateAnimation = new DoubleAnimation(Width / 4, new Duration(TimeSpan.FromMilliseconds(500)));

            BezierSegment bs =
                new BezierSegment(new Point(0, 1), new Point(1, 0.5), new Point(2, 1), true);

            PathGeometry path = new PathGeometry();
            PathFigure figure = new PathFigure();
            figure.StartPoint = new Point(0, 1);
            figure.Segments.Add(bs);
            figure.IsClosed = false;
            path.Figures.Add(figure);

            DoubleAnimationUsingPath scaleAnimation = new DoubleAnimationUsingPath();
            scaleAnimation.PathGeometry = path;
            scaleAnimation.Source = PathAnimationSource.Y;
            scaleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(500));

            translate.BeginAnimation(TranslateTransform.XProperty, translateAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
		}

		private void AnimateToRightSheet()
        {
            DoubleAnimation translateAnimation = new DoubleAnimation(-Width / 4, new Duration(TimeSpan.FromMilliseconds(500)));

            BezierSegment bs =
                new BezierSegment(new Point(0, 1), new Point(1, 0.5), new Point(2, 1), true);

            PathGeometry path = new PathGeometry();
            PathFigure figure = new PathFigure();
            figure.StartPoint = new Point(0, 1);
            figure.Segments.Add(bs);
            figure.IsClosed = false;
            path.Figures.Add(figure);

            DoubleAnimationUsingPath scaleAnimation = new DoubleAnimationUsingPath();
            scaleAnimation.PathGeometry = path;
            scaleAnimation.Source = PathAnimationSource.Y;
            scaleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(500));

            translate.BeginAnimation(TranslateTransform.XProperty, translateAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
        }

		public void MoveToNextPage()
        {
            if (CurrentPage == BookCurrentPage.LeftSheet)
                AnimateToNextPage(false, 500);
            CurrentPage =
                CurrentPage == BookCurrentPage.LeftSheet ?
                    BookCurrentPage.RightSheet : BookCurrentPage.LeftSheet;
        }

        public void MoveToPreviousPage()
        {
            if (CurrentPage == BookCurrentPage.RightSheet)
                AnimateToPreviousPage(false, 500);
            CurrentPage =
                CurrentPage == BookCurrentPage.LeftSheet ?
                    BookCurrentPage.RightSheet : BookCurrentPage.LeftSheet;
        }

		#region Internal Methods

		internal void OnPageDragging(UBookPage page)
		{
			UBookPage bp0 = GetTemplateChild("sheet0") as UBookPage;
			UBookPage bp1 = GetTemplateChild("sheet1") as UBookPage;
			if (bp0 == page)
			{
				Canvas.SetZIndex((bp0 as UBookPage), 1);
				Canvas.SetZIndex((bp1 as UBookPage), 0);
			}
			else if (bp1 == page)
			{
				Canvas.SetZIndex((bp0 as UBookPage), 0);
				Canvas.SetZIndex((bp1 as UBookPage), 1);
			}
		}

		public object GetPage(int index)
		{
			if ((index >= 0) && (index < Items.Count))
				return Items[index];

			Canvas c = new Canvas();
			c.Background = Brushes.White;

			return c;
		}


		#endregion

		#region IControl Implementation

		#region Private Fields

		private ControlBaseImpl _impl;

		#endregion

		#region Private Methods

		private void InitializeIControlPart()
		{
			_impl = new ControlBaseImpl(this);
			_impl.GotFingerCapture += new UTable.Input.MultiTouch.FingerEventHandler(_impl_GotFingerCapture);
			_impl.LostFingerCapture += new UTable.Input.MultiTouch.FingerEventHandler(_impl_LostFingerCapture);
			this.InputReceived += new UTable.Input.InputEventHandler(_impl_InputReceived);
		}

		void _impl_InputReceived(UTable.Input.InputEventArgs args)
		{
			if (args is UTable.Input.MultiTouch.MultiTouchEventArgs)
				MultiTouchProcessor.RaiseMultiTouchEvent(args as UTable.Input.MultiTouch.MultiTouchEventArgs);
		}

		void _impl_LostFingerCapture(object sender, UTable.Input.MultiTouch.FingerEventArgs args)
		{
			if (LostFingerCapture != null)
				LostFingerCapture(sender, args);
		}

		void _impl_GotFingerCapture(object sender, UTable.Input.MultiTouch.FingerEventArgs args)
		{
			if (GotFingerCapture != null)
				GotFingerCapture(sender, args);
		}

		#endregion

		#region IControl Members

		public UTable.Objects.Controls.ControlInfo Info
		{
			get { return _impl.Info; }
		}

		public UTable.Objects.Handlers.MultiTouchProcessor MultiTouchProcessor
		{
			get { return _impl.MultiTouchProcessor; }
		}

		#endregion

		#region IVisualNode Members

		public String ID
		{
			get { return _impl.ID; }
		}

		public new double Width
		{
			get { return _impl.Width; }
			set { _impl.Width = value; }
		}

		public new double Height
		{
			get { return _impl.Height; }
			set { _impl.Height = value; }
		}

		public new bool IsHitTestVisible
		{
			get { return _impl.IsHitTestVisible; }
			set { _impl.IsHitTestVisible = value; }
		}

		#endregion

		#region IInputNode Members

		public void RaiseEvent(UTable.Input.InputEventArgs e)
		{
			if (InputReceived != null)
			{
				InputReceived(e);
			}
			OnInputReceived(e);
		}

		public virtual void OnInputReceived(UTable.Input.InputEventArgs args)
		{
			_impl.OnInputReceived(args);
		}

		public bool CaptureFinger(int fingerId)
		{
			return _impl.CaptureFinger(fingerId);
		}

		public bool UncaptureFinger(int fingerId)
		{
			return _impl.UncaptureFinger(fingerId);
		}

		public event UTable.Input.MultiTouch.FingerEventHandler GotFingerCapture;

		public event UTable.Input.MultiTouch.FingerEventHandler LostFingerCapture;

		public event UTable.Input.InputEventHandler InputReceived;

		#endregion
		#endregion
    }
    public enum BookDisplayMode { Normal, ZoomOnPage }
    public enum BookCurrentPage { LeftSheet, RightSheet }
    public enum BookPresentMode { TwoPages, OnePage }



}
